package cn.mrlong.base.ktnet

import cn.mrlong.base.ktnet.adapter.MGsonConverterFactory
import cn.mrlong.base.ktnet.baseconfig.ApiConfig
import cn.mrlong.base.ktnet.baseconfig.BaseResponse
import cn.mrlong.base.ktnet.https.SSLSocketClient
import cn.mrlong.base.ktnet.httpssupport.TrustAllCerts
import cn.mrlong.base.ktnet.token.TokenHeaderInterceptor
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import java.security.SecureRandom
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
 * 作者：BINGO
 * 时间：2021/03/26 14:29
 */
class RetrofitManager private constructor() {
    companion object {
        private var instance: RetrofitManager? = null
            get() {
                if (null == field) {
                    field = RetrofitManager()
                }
                return field
            }

        fun get(): RetrofitManager {
            return instance!!;
        }

    }

    var token: String = ""
    var retrofit: Retrofit? = null
    private val DEFAULT_TIME = 12L;
    private var trustAllCerts: TrustAllCerts? = null
    var cookieStore: HashMap<String, List<Cookie>> = HashMap()

    init {
        initRetrofit()
    }

    private fun initRetrofit() {
        retrofit = Retrofit.Builder()
            .baseUrl(ApiConfig.BASE_URL)
            //.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//使用rxjava处理返回数据
            //.addCallAdapterFactory(LiveDataCallAdapterFactory())//使用Livedata处理返回数据
            .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())//使用Livedata处理返回数据
            .addConverterFactory(MGsonConverterFactory.create(BaseResponse::class.java))
            .client(initOkHttp())
            .build()
    }

    private fun initOkHttp(): OkHttpClient {
        trustAllCerts = TrustAllCerts()
        return OkHttpClient.Builder()
            .addInterceptor(TokenHeaderInterceptor())//添加token
            .cookieJar(object : CookieJar {
                override fun loadForRequest(url: HttpUrl): List<Cookie> {
                    val cookies = cookieStore[url.host]
                    return cookies ?: ArrayList()
                }

                override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
                    cookieStore[url.host] = cookies
                }
            })
            .sslSocketFactory(
                SSLSocketClient.getSSLSocketFactory(),
                SSLSocketClient.getX509TrustManager()
            )//支持https
            .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
            .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))//设置输入日志详细
            .retryOnConnectionFailure(true)
            .build()
    }

    private fun createSSLSocketFactory(): SSLSocketFactory {
        var ssfFactory: SSLSocketFactory? = null
        try {
            val sc = SSLContext.getInstance("TLS")
            sc.init(null, arrayOf<TrustManager>(trustAllCerts!!), SecureRandom())
            ssfFactory = sc.socketFactory
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ssfFactory!!
    }

    /**
     * 获取对应的Service
     *
     * @param service Service 的 class
     * @param <T>
     * @return
    </T> */
    fun <T> create(service: Class<T>?): T {
        return retrofit!!.create(service)
    }

    /**
     * 使用rxjava切换线程
     * @param observable Observable<T>
     * @param observer Observer<T>
     */
    public fun <T> subscribe(observable: Observable<T>, observer: Observer<T>) {
        observable.subscribeOn(Schedulers.io())
            .subscribeOn(Schedulers.io()) //子线程访问网络
            .observeOn(AndroidSchedulers.mainThread()) //回调到主线程
            .subscribe(observer)
    }


}

//扩展Retrofit.Call类，为其扩展一个await方法，并标识为挂起函数
suspend fun <T> Call<T>.await(): T {
    return suspendCoroutine {
        enqueue(object : Callback<T> {
            override fun onFailure(call: Call<T>, t: Throwable) {
                //请求失败，抛出异常，手动结束当前协程
                it.resumeWithException(t)
            }

            override fun onResponse(call: Call<T>, response: Response<T>) {
                if (response.isSuccessful) {
                    //请求成功，将请求结果拿到并手动恢复所在协程
                    it.resume(response.body()!!)
                } else {
                    //请求状态异常，抛出异常，手动结束当前协程
                    it.resumeWithException(Throwable(response.toString()))
                }
            }
        })
    }
}